
#ifndef TOOLS_H
#define TOOLS_H

//{{{ file documentation -------------------------------------------------------

/*!
 * @file     tools.h
 * @brief    dicodor tools class declaration ...
 */

//}}} --------------------------------------------------------------------------
//{{{ includes / predeclarations -----------------------------------------------

// @(#) $Id: tools.h 77 2012-11-06 13:52:17Z papajaac $

#include <QtCore/QDebug>
#include <QtCore/QElapsedTimer>

#include <QtGui/QWidget>
#include <QtGui/QDesktopWidget>
#include <QtGui/QMessageBox>

//}}} --------------------------------------------------------------------------
//{{{ macros -------------------------------------------------------------------

#define CHRONO_START    QElapsedTimer __chronoPPJ; __chronoPPJ.start();
#define CHRONO_END      qDebug() << QString("%1 exécuté en %2 ms").arg(Q_FUNC_INFO).arg(__chronoPPJ.elapsed());

//}}} --------------------------------------------------------------------------
//{{{ structures ---------------------------------------------------------------
//}}} --------------------------------------------------------------------------
//{{{ class Tools --------------------------------------------------------------

class				Tools
{
private:
	Tools ();

public:
	template <typename T>
	static T	abs (const T & a)											{ return max (a, -a); }

	template <typename T>
	static T	min (const T & a, const T & b)								{ if (a < b) return a; return b; }
	template <typename T>
	static T	min (const T & a, const T & b, const T & c)					{ return min (a, min (b, c)); }
	template <typename T>
	static T	min (const T & a, const T & b, const T & c, const T & d)	{ return min (min (a, b), min (c, d)); }

	template <typename T>
	static T	min (const QList<T> & list) {
		switch (list.size ()) {
		case 0:
		return T ();
		break;

		case 1:
		return list.at (0);
		break;

		case 2:
		return min (list.at (0), list.at (1));
		break;

		case 3:
		return min (list.at (0), list.at (1), list.at (2));
		break;

		case 4:
		return min (list.at (0), list.at (1), list.at (2), list.at (3));
		break;

		default:
		{
			T result = list.at (0);

			for (int indice = 1 ; indice < list.count () ; indice++) {
				const T & tempo (list.at (indice));
				if (tempo < result)	result = tempo;
			}

			return result;
			break;
		}
		}
	}

	template <typename T>
	static T	max (const T & a, const T & b)								{ if (a > b) return a; return b; }
	template <typename T>
	static T	max (const T & a, const T & b, const T & c)					{ return max (a, max (b, c)); }
	template <typename T>
	static T	max (const T & a, const T & b, const T & c, const T & d)	{ return max (max (a, b), max (c, d)); }

	template <typename T>
	static T	max (const QList<T> & list) {
		switch (list.size ()) {
		case 0:
		return T ();
		break;

		case 1:
		return list.at (0);
		break;

		case 2:
		return max (list.at (0), list.at (1));
		break;

		case 3:
		return max (list.at (0), list.at (1), list.at (2));
		break;

		case 4:
		return max (list.at (0), list.at (1), list.at (2), list.at (3));
		break;

		default:
		{
			T result = list.at (0);

			for (int indice = 1 ; indice < list.count () ; indice++) {
				const T & tempo (list.at (indice));
				if (tempo > result)	result = tempo;
			}

			return result;
			break;
		}
		}
	}



	// manipulation de bits

	static int		bit( const uchar * data, const int num );
	static int		bitLSB( const uchar * data, const int num );

	static void		setBit( uchar * data, const int num );
	static void		setBitLSB( uchar * data, const int num );

	static void		clearBit( uchar * data, const int num);
	static void		clearBitLSB( uchar * data, const int num );

	static void		memCpy( quint8 * dest, const quint8 * source, const int count );

	// copie d'un fichier par blocs
	static bool		fileCopyByBlocks (const QString & srcName, const QString & dstName, const int bufferSize);

	// type d'un fichier sous Linux ou MacOS
	static QString	fileType (const QString &path);

	// appel d'une commande shell
	static QString	shell (const QString &cmdLine);

	// gestion de l'environnement
	static QString	environmentValue (const QString &name);
	static void		setEnvironmentValue (const QString &name, const QString &value);

	// facilitateur
	static bool		userAgrees (const QString &text);
	QString getUserName ();
	QString getenv (QString var);
	void wait (int ms);
	QString DEName();
};

//}}} --------------------------------------------------------------------------
//{{{ inline / template functions ----------------------------------------------

inline Tools::Tools () {}

inline int  Tools::bit ( const uchar * data, const int num )		{ return( data[num >> 3] >> (7 -(num & 7))) & 1; }
inline int  Tools::bitLSB ( const uchar * data, const int num )	{ return( data[num >> 3] >>     (num & 7))  & 1; }

inline void Tools::setBit ( uchar * data, const int num )			{ data[num >> 3] |=  (1 << (7 - (num & 7))); }
inline void Tools::setBitLSB ( uchar * data, const int num )		{ data[num >> 3] |=  (1 <<      (num & 7));  }

inline void Tools::clearBit ( uchar * data, const int num )		{ data[num >> 3] &= ~(1 << (7 - (num & 7))); }
inline void Tools::clearBitLSB ( uchar * data, const int num )	{ data[num >> 3] &= ~(1 <<      (num & 7));  }

inline void Tools::memCpy ( quint8 * dest, const quint8 * source, const int count )
{
	for (int index = 0 ; Q_LIKELY (index != count / 4) ; index++) *(quint32 *) dest++ = *(quint32*) source++;
	for (int index = 0 ; Q_LIKELY (index != count % 4) ; index++) *(quint8  *) dest++ = *(quint8 *) source++;
}

//}}} --------------------------------------------------------------------------

#include <QFileInfo>
#include <QDir>

/**
 * @brief The FileName class
 */
class FileName : public QFileInfo
{
public:
	FileName (const QString& fullPath) : QFileInfo (fullPath) {}

	QString path () const { return canonicalPath () % "/"; }
	bool setPath (const QString& p) {
		setFile (p % name () % extension ());
		return exists ();
	}

	QString name () const { return baseName (); }
	bool setName (const QString& n) {
		setFile (path () % n % extension ());
		return exists ();
	}

	QString extension () const { return "." % completeSuffix (); }
	bool setExtension (const QString& e) {
		setFile (path () % name () % e);
		return exists ();
	}

	QString completeName () const { return path () % name () % extension (); }
};


/**
 * @brief The Rgb class
 */

#ifndef BLACK
#define BLACK   (0xff000000)
#endif

#ifndef WHITE
#define WHITE   (0xffffffff)
#endif

#define CRED		(quint16 (306))
#define CGREEN	(quint16 (601))
#define CBLUE	(quint16 (117))

class Rgb {
private:
	union	{
		struct {
			quint8 m_alpha;
			quint8 m_red;
			quint8 m_green;
			quint8 m_blue;
		};
		QRgb m_color;
	};

public:
	inline Rgb (const QRgb color = WHITE) : m_color (color) {}
	inline Rgb (const Rgb& other) : m_color (other.m_color) {}
	inline Rgb (const Rgb* other) : m_color (other->m_color) {}

	inline quint8 alpha () const { return m_alpha; }
	inline quint8 red () const { return m_red; }
	inline quint8 green () const { return m_green; }
	inline quint8 blue () const { return m_blue; }

	inline void setAlpha (const quint8 a) { m_alpha = a; }
	inline void setRed (const quint8 r) { m_red = r; }
	inline void setGreen (const quint8 g) { m_green = g; }
	inline void setBlue (const quint8 b) { m_blue = b; }
	inline bool isGray () const { return red () == blue () && green () == blue (); }

	inline QRgb argb () const { return m_color; }
	inline void setArgb (const QRgb color) { m_color = color; }
	inline void setArgb (const quint8 a, const quint8 r, const quint8 g, const quint8 b)	{
		setAlpha (a); setRed (r); setGreen (g); setBlue (b);
	}

	inline QRgb rgb () const { return argb () & 0x00ffffff; }
	inline void setRgb (const QRgb color) { setArgb (color) ; setAlpha (0xff); }
	inline void setRgb (const quint8 r, const quint8 g, const quint8 b)	{
		setAlpha (0xff); setRed (r); setGreen (g); setBlue (b);
	}

	inline void operator = (const QRgb color) { m_color = color; }

	inline bool operator == (const QRgb c) const { return m_color == c; }

	inline void toGray () { const quint8 b = brightness (); setRgb (b,b,b); }
	inline quint8 brightness () const	{
		return (red () * CRED + green () * CGREEN + blue () * CBLUE) >> 10;
	}

	inline void invertColor () { quint8 a = alpha () ; setRgb (~m_color); setAlpha (a); }

	inline int colorDistance (const Rgb& c2) const {
		return Tools::abs (red () - c2.red ())
				+ Tools::abs (green () - c2.green ())
				+ Tools::abs (blue () - c2.blue ());
	}

	// static
	static inline quint8 toAlpha (const QRgb c) { Rgb tmp (c); return tmp.alpha (); }
	static inline quint8 toRed (const QRgb c) { Rgb tmp (c); return tmp.red (); }
	static inline quint8 toGreen (const QRgb c) { Rgb tmp (c); return tmp.green (); }
	static inline quint8 toBlue (const QRgb c) { Rgb tmp (c); return tmp.blue (); }
	static inline quint8 brightness (QRgb c)	{
		return (toRed (c) * CRED + toGreen (c) * CGREEN + toBlue (c) * CBLUE) >> 10;
	}
};

#endif // TOOLS_H

